# Copyright (C) 2006  Apptility LLC  http://www.apptility.com
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# version 2.1 of the License, or (at your option) any later version.
#
# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this library; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA

require 'feed_tools'
require 'date'

class FeedAggregator < ActiveRecord::Base
  # type of logging incorporated, if logfile, then log to the file, if console, log to console
  # Though FeedAggregator is going to run under cron, log to the file
  $LOG_CONSOLE = "logfile"
  $LOG_TOKEN ="FeedAggregator:"
  $LOG_TOKEN_VER ="Ver1.0:"
  
  def self.aggregate_and_deliver
    aggregate
  end
  
  def self.aggregate
    # for now get all the feeds, later get feeds based on subscription pattern may be
    # e.g. first pick up feeds which are daily delivery, then weekly and then monthly.
    @allfeeds = list_all_feeds
    for feed in @allfeeds  
      @feedu = FeedTools::Feed.open(feed.feed_url)
      #feed.last_updated_time = get_date_obj(@feedu.updated.to_s)
      #feed.save
      
      is_feed_changed = is_feed_changed_since_lasttime(feed, @feedu)
      if is_feed_changed
        logData("####p:Fetched Feed : #{feed.feed_url} has changed, so aggregating, sit tight..")
        # Update the current feed time first
        feed.last_updated_time = get_date_obj(@feedu.updated.to_s)
        feed.save
        # Now aggregate feed posts
        aggregate_feed_posts(feed, @feedu)
      else
        logData("####p:Fetched Feed : #{feed.feed_url} has not changed so skipping this one.")  
      end  
    end 
  end

  def self.aggregate_feed_posts(dbFeedObj, liveFeedObj)
    # first get existing feeds with guid from feed posts, came from liveFeedObj object
    # update feeds which are modified, delete feeds which are not modified
   for feed_item in liveFeedObj.items
      feedRecord = FeedPostUpdate.find(:first, :conditions=>["post_guid = ?", feed_item.id])
      if(feedRecord==nil) 
        # this means new feed post , add it to the db
        create_new_feed_post(liveFeedObj, feed_item)
      else
        # update or delete the feed posts
        if(is_feed_post_changed(feedRecord, feed_item))
          update_feed_post(feedRecord, feed_item, liveFeedObj)
        else
          delete_feed_post(feedRecord, feed_item)
        end
      end 
    end
  end
  
  def self.delete_feed_post(feedPostUpdate, feed_item)
    #feedPostUpdate.destroy
    feedPostUpdate.is_alive = 0
    feedPostUpdate.save
    logData("Disabled feed post : [#{feed_item.title}] ")
    logData("-----------------------------------------------------------------------")
  end
  
  def self.update_feed_post(feedPostUpdate, feed_item, liveFeedObj)
      #feedPostUpdate.feed_id = liveFeedObj.id
      feedPostUpdate.post_title = feed_item.title
      feedPostUpdate.post_url = feed_item.link
      feedPostUpdate.post_content = feed_item.description
      feedPostUpdate .post_modified = get_feed_item_update_date(feed_item)
      feedPostUpdate.is_alive = 1
      feedPostUpdate.save
      logData("Updated feed post : [#{feedPostUpdate.post_title}] ")
      logData("-----------------------------------------------------------------------")
  end
  
  def self.create_new_feed_post(liveFeedObj, feed_item)
      @feedPostUpdate  = FeedPostUpdate.new()
      @feedPostUpdate.feed_id = liveFeedObj.id
      @feedPostUpdate.post_title = feed_item.title
      @feedPostUpdate.post_url = feed_item.link
      @feedPostUpdate.post_content = feed_item.description
      @feedPostUpdate.post_modified = get_feed_item_update_date(feed_item)
      @feedPostUpdate.post_guid = feed_item.id
      @feedPostUpdate.is_alive = 1
      @feedPostUpdate.save
      logData("New feed post has been added : [#{@feedPostUpdate.post_title}] ")
      logData("-----------------------------------------------------------------------")
  end
  
  def self.is_feed_post_changed(db_feed_post_obj, live_feed_item__obj)
     live_feed_item_updated_date = get_feed_item_update_date(live_feed_item__obj)
     live_feed_item_updated_date_obj = get_date_obj(live_feed_item_updated_date.to_s)
     db_feed_post_date_obj = get_date_obj(db_feed_post_obj.post_modified.to_s)
     logData("DB [#{db_feed_post_obj.post_title}] Feed Post Time : [#{db_feed_post_date_obj}]<=>Real Feed Item Time : [#{live_feed_item_updated_date_obj}] ")
     if live_feed_item_updated_date_obj > db_feed_post_date_obj
     #if liveFeedObj.updated > dbFeedObj.last_updated_time
        return true 
     else 
        return false
     end 
  end
  
  def self.is_feed_changed_since_lasttime(dbFeedObj, liveFeedObj)
     
     liveFeedObjDateTime = get_date_obj(liveFeedObj.updated.to_s)
     dbFeedObjDateTime = get_date_obj(dbFeedObj.last_updated_time.to_s)
     logData("DB FeedTime : [#{dbFeedObjDateTime}]<=>Real FeedTime : [#{liveFeedObjDateTime}] ")
     if liveFeedObjDateTime > dbFeedObjDateTime
     #if liveFeedObj.updated > dbFeedObj.last_updated_time
        return true 
     else 
        return false
     end 
  end
  
  # This method is used, because Atom and RSS use different date types/names
  def self.get_feed_item_update_date(feed_item)
       if(feed_item.updated!=nil)
        return feed_item.updated
      else
        return feed_item.published
      end  
  end
  
  def self.get_date_obj(dateobjectstring)
    return Time.parse(dateobjectstring).strftime("%m/%d/%Y %H:%M:%S")
  end
  
  def self.list_all_feeds
    @allfeeds = Feed.find(:all)
  end
  
  def self.logData(debugString)
    if($LOG_CONSOLE=='logfile')
      Odotcron.logInfo("#{$LOG_TOKEN} #{$LOG_TOKEN_VER}:"<<debugString)
    end  
  end
  
end
